#!/bin/sh

## Setup is basically thus:
##
## On your server:
##
## $ mkdir -p production.git /path/to/website
## $ cd production.git
## $ git init --bare
## $ git config core.worktree /path/to/website/son
## $ git config core.bare false
## $ git config receive.denycurrentbranch ignore
## $ git config eregansu.rotate true
## $ cp wherever-this-file-is hooks/post-receive
## $ chmod +x hooks/post-receive
## $ mkdir /path/to/website/shared
## $ mkdir /path/to/website/private
## $ chmod 733 /path/to/website/private
##
## On the client:
##
## $ git remote add production user@server.example.com:production.git
## $ git push production master
##
## Configure your web server to look at /path/to/website/current as its
## DocumentRoot (or whatever your server's equivalent is).
##
## The configuration above will rotate previous releases so that they
## can be very rapidly reverted with no knowledge of git, should something
## be pushed which shouldn't have been.
##
## For a development/staging site, you probably want to disable rotation,
## in which case the 'core.worktree' and 'eregansu.worktree' configuration
## lines above should be:
##
## $ git config core.worktree /path/to/website/current
## $ git config eregansu.rotate false
##
## Note that in a non-rotating configuration, if the setup phase
## fails, you'll be left with a broken deployment.
##
## There are two additional hook files which you can create, pre-deploy
## and post-deploy. In a rotating configuration, the pre-deploy hook
## is executed in the 'son' subdirectory, prior to it becoming 'current'.
## The post-deploy hook is executed immediately after it has been. In both
## cases, the current directory is that of the newly checked out release.
##
## In a non-rotating configuration, both pre-deploy and post-deploy hooks
## are executed right after 'current' has been updated.
##
## Once configured, you can simply 'git push production master' to
## deploy your master branch to the production server.

worktree="`git config --get core.worktree`"
if test x"$worktree" = x"" ; then
	echo "**** Detached working tree has not been configured for this repository; aborting" >&2
	exit 1
fi
test -d "$worktree" || mkdir "$worktree"
deploy_to=`( cd $worktree/.. && pwd)`
here=`pwd`
rotate="`git config --bool --get eregansu.rotate`"
appname="`git config --get eregansu.application`"
instname="`git config --get eregansu.instance`"
onlybranch="`git config --get eregansu.branch`"

read oldrev newrev refname

if test x"$onlybranch" = x"" ; then
	true
else
	if test x"$refname" = x"refs/heads/$onlybranch" ; then
		true
	else
		echo "==> Skipping $newrev as $refname is not the deployment branch" >&2
		exit 0
	fi
fi

test x"$rotate" = x"" && rotate=false
test x"$GIT_DIR" = x"" && GIT_DIR="."
GIT_DIR="`cd $GIT_DIR && pwd`"
export GIT_DIR

if test x"$rotate" = x"true" ; then
	echo "==> Performing pre-deployment checkout in $deploy_to" >&2
	rm -rf "$worktree" || exit $?
	mkdir "$worktree" || exit $?
	cd "$worktree" || exit $?
	git checkout -f || exit $?
	echo "==> Updating submodules" >&2
	git submodule update --init || exit $?

	cd "$deploy_to" || exit $?
	echo "==> Rotating previous releases" >&2
	if test -L grandfather ; then
		target="`readlink grandfather`"
		echo "==> Removing grandfather version $target" >&2
		rm -rf "$target"
	fi
	rm -f grandfather

	if test -L father ; then
		target="`readlink father`"
		echo "==> Revision $target is now grandfather" >&2
        ln -s "$target" grandfather
	fi
	rm -f father

	if test -L son ; then
		target="`readlink son`"
		echo "==> Revision $target is now father" >&2
        ln -s "$target" father
	fi
	rm -f son

	echo "==> Revision $newrev is now son" >&2
	mv worktree "$newrev"
	worktree="$deploy_to/$newrev"
	ln -s "$newrev" son

	cd "$deploy_to/$newrev" || exit $?

	echo "==> Setting up the new release $newrev" >&2
	if test -x "$GIT_DIR/hooks/pre-deploy" ; then
		( cd "$worktree" && "$GIT_DIR/hooks/pre-deploy" ) || exit $?
	fi

	if test -d "$worktree/eregansu" ; then
		if test -x "$worktree/cli" ; then
			true
		else
			( cd "$worktree" && rm -f cli && ln -s eregansu/cli cli ) || exit $?
		fi
	else
		echo "$0: warning: $worktree/eregansu is not present" >&2
	fi

	if test -r "$worktree/config/appconfig.php" ; then
		true
	elif test x"$application" = x"" ; then
		echo "$0: warning: configuration option eregansu.application is unset, cannot link $worktree/config/appconfig.php" >&2
	elif test -r "$worktree/config/appconfig.$application.php" ; then
		echo "  +> Symbolically linking config/appconfig.$application.php" >&2
		rm -f "$worktree/config/appconfig.php" || exit $?
		( cd "$worktree/config" && ln -s "appconfig.$application.php" appconfig.php ) || exit $?
	else
		echo "$0: warning: $worktree/config/appconfig.$application.php does not exist; cannot create link to appconfig.php" >&2		
	fi

	if test -r "$worktree/config/config.php" ; then
		true
	elif test x"$instance" = x"" ; then
		echo "$0: warning: configuration option eregansu.instance is unset, cannot link $worktree/config/instance.php" >&2
	elif test -r "$worktree/config/config.$instance.php" ; then
		echo "  +> Symbolically linking config/config.$instance.php" >&2
		rm -f "$worktree/config/config.php" || exit $?
		( cd "$worktree/config" && ln -s "config.$instance.php" config.php ) || exit $?
	else
		echo "$0: warning: $worktree/config/config.$instance.php does not exist; cannot create link to config.php" >&2		
	fi

	if test -x "$worktree/cli" ; then
		( cd "$worktree" && ./cli setup ) || exit $?
	else
		echo "$0: warning: $worktree/cli is not present; skipping module setup" >&2
	fi

	if test -d "$deploy_to/shared" ; then
		cd "$deploy_to/shared"
		for i in * ; do
			if test x"$i" = x"public" ; then
				true
			elif test -e "$i" ; then				
				echo "  +> Symlinking /$i" >&2
				( cd "$worktree" && rm -f "$i" && ln -s ../shared/"$i" . ) || exit $?
			fi
		done
	fi
	
	echo "==> Making $newrev current" || exit $?
	cd "$deploy_to" || exit $?
	rm -f current && ln -s "$newrev" "current"
else
    test -d "$worktree" || mkdir "$worktree" || exit $?
    git checkout -f || exit $?
	
    echo "==> Setting up the new release" >&2
	if test -x "$GIT_DIR/hooks/pre-deploy" ; then
		( cd "$worktree" && "$GIT_DIR/hooks/pre-deploy" ) || exit $?
	fi
	if test -d "$deploy_to/shared" ; then
		cd "$deploy_to/shared"
		for i in * ; do
			if test -e "$i" ; then
				echo "  +> Symlinking /$i" >&2
				( cd "$worktree" && rm -f "$i" && ln -s ../shared/"$i" . ) || exit $?
			fi
		done
	fi
fi

if test -x "$GIT_DIR/hooks/post-deploy" ; then
	echo "==> Performing post-deploying tasks" >&2
	( cd "$worktree" && "$GIT_DIR/hooks/post-deploy" ) || exit $?	
fi

echo "==> New release successfully deployed." >&2
